from django.db import transaction
from rest_framework.authentication import TokenAuthentication, BasicAuthentication
from rest_framework.decorators import api_view, authentication_classes, permission_classes
from rest_framework.exceptions import ValidationError
from rest_framework.permissions import IsAuthenticated
from rest_framework.request import Request
from rest_framework.response import Response

from api.conf import order_status
from api.serializers.address_serializer import MailingAddressSerializer
from api.serializers.pay_method_serializer import PayMethodSerializer
from api.serializers.pre_order_serializer import PreOrderAddSerializer, PreOrderReAddSerializer
from app.models import Cart, MailingAddress, ProductSpec
from app.models.pay_method import PayMethod
from app.models.pre_order import PreOrder, PreOrderSpec


@api_view(['POST'])
@authentication_classes((TokenAuthentication, BasicAuthentication))
@permission_classes((IsAuthenticated,))
@transaction.atomic
def add_pre_order(request: Request):
    serializer = PreOrderAddSerializer(data=request.data)
    if serializer.is_valid():
        cart_ids = [cart["cart_id"] for cart in serializer.data['carts']]
        carts = Cart.objects.select_for_update().filter(id__in=cart_ids)
        order_sum = 0
        all_deposit = 0
        for cart in carts:
            if cart.spec.discount:
                order_sum += cart.amount * cart.spec.discount
            else:
                order_sum += cart.amount * cart.spec.price
            all_deposit += cart.amount * cart.spec.deposit
        pre_order = PreOrder.objects.create(user=request.user)
        for cart in carts:
            PreOrderSpec.objects.create(pre_order=pre_order, spec=cart.spec, amount=cart.amount)
            cart.delete()  # 清空购物车
        # 获取默认地址
        try:
            default_address = MailingAddress.objects.get(user=request.user, is_default=True)
        except MailingAddress.DoesNotExist:
            default_address = None

        # 获取支付方式列表，按优先级排序
        pay_methods = list(PayMethod.objects.all().order_by('priority').reverse())

        data = dict(pre_order_id=pre_order.id,
                    sum=order_sum + all_deposit,
                    deposit=all_deposit,
                    pay_methods=PayMethodSerializer(pay_methods, many=True).data,
                    products=[create_product_dict_from_cart(cart) for cart in carts])
        if default_address:
            data['address'] = MailingAddressSerializer(default_address).data

        return Response(data=data)
    else:
        raise ValidationError(serializer.errors)


@api_view(['POST'])
@authentication_classes((TokenAuthentication, BasicAuthentication))
@permission_classes((IsAuthenticated,))
@transaction.atomic
def re_add_pre_order(request: Request):
    serializer = PreOrderReAddSerializer(data=request.data)
    if serializer.is_valid():
        order = serializer.validated_data['order_id']
        if order.user != request.user or order.status != order_status.FINISHED:
            raise ValidationError(detail=u'订单不正确')
        order_products = order.products.all()
        specs = ProductSpec.objects.select_for_update().filter(id__in=order_products)
        order_sum = 0
        all_deposit = 0
        order_specs = {}
        for spec in specs:
            for product in order_products:
                if spec.id == product.id:
                    order_specs[spec] = product.amount
                    if spec.discount:
                        order_sum += product.amount * spec.discount
                    else:
                        order_sum += product.amount * spec.price
                    all_deposit += product.amount * spec.deposit
        pre_order = PreOrder.objects.create(user=request.user)
        for order_spec, amount in order_specs.items():
            PreOrderSpec.objects.create(pre_order=pre_order,
                                        spec=order_spec,
                                        amount=amount)
        # 获取默认地址
        try:
            default_address = MailingAddress.objects.get(user=request.user, is_default=True)
        except MailingAddress.DoesNotExist:
            default_address = None

        # 获取支付方式列表，按优先级排序
        pay_methods = list(PayMethod.objects.all().order_by('priority').reverse())

        data = dict(pre_order_id=pre_order.id,
                    sum=order_sum + all_deposit,
                    deposit=all_deposit,
                    pay_methods=PayMethodSerializer(pay_methods, many=True).data,
                    products=[create_product_dict_from_spec(spec, amount) for spec, amount in order_specs.items()])
        if default_address:
            data['address'] = MailingAddressSerializer(default_address).data

        return Response(data=data)
    else:
        raise ValidationError(serializer.errors)


def create_product_dict_from_cart(cart: Cart):
    return {
        'product_id': cart.spec.product.id,
        'product_name': cart.spec.product.name,
        'product_image': cart.spec.product.image_url,
        'spec_id': cart.spec.id,
        'spec_name': cart.spec.name,
        'price': cart.spec.price,
        'unit': cart.spec.unit,
        'amount': cart.amount,
        'deposit': cart.spec.deposit,
        'deposit_desc': cart.spec.deposit_desc,
        'discount': cart.spec.discount
    }


def create_product_dict_from_spec(spec: ProductSpec, amount):
    return {
        'product_id': spec.product.id,
        'product_name': spec.product.name,
        'product_image': spec.product.image_url,
        'spec_id': spec.id,
        'spec_name': spec.name,
        'price': spec.price,
        'unit': spec.unit,
        'amount': amount,
        'deposit': spec.deposit,
        'deposit_desc': spec.deposit_desc,
        'discount': spec.discount
    }
